#include "AB.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>

int copiarSubArbol(TAB *origen, TAB* destino, int movim){
	int error;
	TNodoAB *auxCorrienteOrigen;
	TNodoAB *auxCorrienteDestino;

	/*Preorder grosssooo*/
	auxCorrienteOrigen = origen->cte; /*Guardo el lugar donde estoy ahora en el arbol origen*/

	AB_Insertar(destino, movim, origen->cte->elem, &error);
	auxCorrienteDestino = destino->cte; /*Guardo el lugar donde estoy ahora en el arbol destino*/


	AB_MoverCte(origen, IZQ, &error);
	if (!error){
		copiarSubArbol(origen,destino, IZQ);
	}

	origen->cte = auxCorrienteOrigen; /*vuelvo a estar donde estaba.... */
	destino->cte =auxCorrienteDestino;

	AB_MoverCte(origen, DER, &error);
	if (!error){
		copiarSubArbol(origen,destino, DER);
	}
	return 0;
}

int AB_CopiarSubarbol( const TAB* origen, TAB* destino, int movim) {
	int error;
	TNodoAB *auxCorriente;
	TAB origen2;

	origen2 = *origen;
	AB_Crear(destino, origen2.tamdato); /* Emo: No es que no se pueden usar primitivas del tipo dentro de otras primitivas? Para mi es una estupidez... pero por ahi joden... */

	auxCorriente = origen2.cte->elem; /* guardo el lugar donde estoy ahora */

	AB_MoverCte(&origen2,movim,&error); /* Emo: Idem arriba */

	copiarSubArbol(&origen2, destino, RAIZ); /* meto el primero en la raiz del nuevo arbolo */

	return 0; /* Emo: En la consigna dice que deberia devolver 1 si pudo copiar, 0 si no */
}

void pegarSubArbolRec( TAB* origen, TAB* destino, int movim)
{
    int error;
    TNodoAB *auxOrigenCte;
	TNodoAB *auxDestinoCte;


    /* Copio el corriente al destino */
    if(origen->cte->elem)
        AB_Insertar(destino, movim, origen->cte->elem, &error);

    /* Guardo el corriente del origen y destino */
    auxOrigenCte = origen->cte;
    auxDestinoCte = destino->cte;

    /* Muevo a izquierda */
    AB_MoverCte(origen, IZQ, &error);
    if(!error)
        pegarSubArbolRec(origen, destino, IZQ);

    /* Vuelvo los corrientes del origen y destino a donde estaban */
    origen->cte = auxOrigenCte;
    destino->cte = auxDestinoCte;

    /* Muevo a derecha */
    AB_MoverCte(origen, DER, &error);
    if(!error)
        pegarSubArbolRec(origen, destino, DER);
}

int AB_PegarSubarbol( const TAB* origen, TAB* destino, int movim)
{
    TAB auxOrigen;
    TNodoAB* abcte;

    /* Chequeo si puedo pegar el arbol origen en el hijo <movim> del corriente del destino */
    if(movim == IZQ && destino->cte->izq)
        return 0;
    else if(movim == DER && destino->cte->der)
        return 0;

    /* Copio el origen para mantener el const */
    auxOrigen = *origen;

    /* Muevo el corriente del origen a la raiz */
    abcte=destino->cte;
    auxOrigen.cte = auxOrigen.raiz;

    /* Llamado inicial a la funcion recursiva */
    pegarSubArbolRec(&auxOrigen, destino, movim);

    destino->cte=abcte;

    return 1;
}


void AB_Crear(TAB *a,int tdato)
{
    a->tamdato = tdato;
    a->raiz = NULL;
    a->cte = NULL;
}


void AB_ElemCte(TAB a,void *elem)
{
    memcpy(elem,a.cte->elem,a.tamdato);
}


void AB_ModifCte(TAB *a,void *elem)
{
    memcpy(a->cte->elem,elem,a->tamdato);
}


TNodoAB* BuscarPadre(TNodoAB *padre,TNodoAB *hijo)
{
    TNodoAB *paux = NULL;
    if ((padre->izq == hijo) || (padre->der == hijo))
        return padre;
    else
    {
        if (padre->izq != NULL)
            paux = BuscarPadre(padre->izq,hijo);
        if ((padre->der != NULL) && (paux == NULL))
            paux = BuscarPadre(padre->der,hijo);

        return paux;
    }
}


void AB_MoverCte(TAB *a,int mov,int *error)
{
    *error = 0;
    switch (mov)
    {
        case IZQ:
            if (a->cte->izq != NULL)
                a->cte = a->cte->izq;
            else
                *error = 1;
            break;

        case DER:
            if (a->cte->der != NULL)
                a->cte = a->cte->der;
            else
                *error = 1;
            break;

        case PAD:
            if (a->cte != a->raiz)
                a->cte = BuscarPadre(a->raiz,a->cte);
            else
                *error = 1;
            break;

        case RAIZ:
            if (a->raiz != NULL)
                a->cte = a->raiz;
            else
                *error = 1;
            break;

        default :
            *error = 1;
    }
}

void VaciarSub(TNodoAB *pnodo)
{
    if (pnodo != NULL)
    {
        if ((pnodo->izq == NULL) && (pnodo->der == NULL))
        {
            free(pnodo->elem);
            free(pnodo);
        }
        else
        {
            VaciarSub(pnodo->izq);
            VaciarSub(pnodo->der);
            free(pnodo->elem);
            free(pnodo);
        }
    }
}


void AB_Vaciar(TAB *a)
{
    VaciarSub(a->raiz);
    a->raiz = NULL;
    a->cte = NULL;
}


void AB_Insertar(TAB *a,int mov,void *elem,int *error)
{
    TNodoAB *paux;
    *error = 0;
    paux = (TNodoAB*) malloc(sizeof(TNodoAB));
    paux->izq = NULL;
    paux->der = NULL;
    if (paux)
    {
        paux->elem = malloc(a->tamdato);
        if (paux->elem)
        {
            memcpy(paux->elem,elem,a->tamdato);
            switch(mov)
            {
                case IZQ:
                    if (a->cte->izq == NULL)
                        a->cte->izq = paux;
                    else
                        *error = 1;
                    break;

                case DER:
                    if (a->cte->der == NULL)
                        a->cte->der = paux;
                    else
                        *error = 1;
                    break;

                case RAIZ:
                    if (a->raiz == NULL)
                        a->raiz = paux;
                    else
                        *error = 1;
                    break;

                default:
                    *error = 1;
            }
            if (*error)
            {
                free(paux->elem);
                free(paux);
            }
            else /* Si puedo insertar, setea al nuevo elemento como el corriente */
                a->cte = paux;
        }
        else /* if (paux->elem) */
        {
            *error = 1;
            free(paux);
        }
    }
    else /* if (paux) */
        *error = 1;
}


int AB_Vacio(TAB a)
{
    if (a.raiz == NULL)
        return 1;
    else
        return 0;
}
